home *** CD-ROM | disk | FTP | other *** search
- ;* UTILS.ASM
- ;************************************************************************
- ;* *
- ;* PC Scheme/Geneva 4.00 Borland TASM code *
- ;* *
- ;* (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT *
- ;* (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva *
- ;* *
- ;*----------------------------------------------------------------------*
- ;* *
- ;* Utilities, including C--Asm linkages *
- ;* *
- ;*----------------------------------------------------------------------*
- ;* *
- ;* Created by: John Jensen Date: 1985 *
- ;* Revision history: *
- ;* - 25 Feb 86: Added the routine "put_ptr" to combine the *
- ;* "put_byte/put_word" operations when a pointer is being stored *
- ;* into memory. (JCJ) *
- ;* - 18 Jun 92: Renaissance (Borland Compilers, ...) *
- ;* *
- ;* ``In nomine omnipotentii dei'' *
- ;************************************************************************
- IDEAL
- %PAGESIZE 60, 132
- MODEL medium
- LOCALS @@
-
- INCLUDE "scheme.ash"
-
- CODESEG
-
- ;************************************************************************
- ;* Zero a page in memory - Calling sequence: zero_page(page_no) *
- ;************************************************************************
- PROC C zero_page USES di, @@page:WORD
- mov bx, [@@page]
- sal bx, 1
- ldpage es, bx
- xor ax, ax
- xor di, di
- mov cx, [psize+bx]
- shr cx, 1
- cld
- rep stosw
- ret
- ENDP zero_page
-
- ;************************************************************************
- ;* Zero a block of memory *
- ;* *
- ;* Purpose: To initialize a variable length block of memory to zero. *
- ;* *
- ;* Description: The block is zeroed using the 8088's "store string" *
- ;* instruction using a repeat count. For *
- ;* efficiency reasons, the zeroing is done by *
- ;* words, with a fixup to account for blocks with *
- ;* an odd number of bytes. *
- ;* *
- ;* Calling sequence: zero_blk(page_no, disp) *
- ;* where page_no = page number (C's unshifted page number) *
- ;* disp = displacement of block within the page *
- ;************************************************************************
- PROC C zero_blk USES di, @@page:WORD, @@disp:WORD
- mov bx, [@@page]
- shl bx, 1 ; and adjust for use as index
- mov di, [@@disp]
- ldpage es, bx
- mov cx, [(ANYDEF es:di).len]
- add di, OFFSET (TYPE ANYDEF).data
- or cx, cx
- jge @@bigstring
- add cx, SIZE POINTER
- jmp @@cont
- @@bigstring:
- sub cx, OFFSET (TYPE ANYDEF).data
- @@cont:
- xor ax, ax ; load a value of zero into ax
- shr cx, 1 ; convert number of bytes to number of words
- cld
- rep stosw
- jnc @@even
- stosb ; zero the last byte, if odd number of bytes
- @@even:
- ret
- ENDP zero_blk
-
- ;************************************************************************
- ;* Use a Scheme page in C *
- ;* Calling sequence: *
- ;* LIST far *p; *
- ;* p = (LIST far *) page2c(page); *
- ;* where: page ----- page # *
- ;* p[n] ----- n+1st list cell in the page *
- ;************************************************************************
- PROC C page2c, @@page:WORD
- mov bx, [@@page]
- shl bx, 1 ; adjust it for segment lookup
- ldpage ax, bx
- ret
- ENDP page2c
-
- PROC C scheme2c, @@page:WORD, @@disp:WORD
- mov bx, [@@page]
- shl bx, 1 ; adjust it for segment lookup
- ldpage dx, bx
- mov ax, [@@disp]
- ret
- ENDP scheme2c
-
- PROC C reg2c, @@reg:WORD
- mov bx, [@@reg]
- ldpage dx, [(REG bx).page]
- mov ax, [(REG bx).disp]
- ret
- ENDP reg2c
-
- ;************************************************************************
- ; Get a register's type
- ; Calling sequence: data = gettype(reg)
- ;************************************************************************
- PROC C gettype, @@reg:WORD, @@disp:WORD
- mov bx, [@@reg]
- mov bx, [(REG bx).page]
- mov ax, [WORD ptype+bx]
- ret
- ENDP gettype
-
- ;************************************************************************
- ; Get a byte of data
- ; Calling sequence: data = get_byte(page, disp)
- ; where: page ----- page number
- ; disp ----- (byte) displacement within page
- ;************************************************************************
- PROC C get_byte, @@page:WORD, @@disp:WORD
- mov bx, [@@page]
- shl bx, 1 ; adjust it for segment lookup
- ldpage es, bx
- mov bx, [@@disp]
- mov al, [BYTE es:bx]
- xor ah, ah ; and only a byte
- ret
- ENDP get_byte
-
- ;************************************************************************
- ; Get a word of data
- ; Calling sequence: data = get_word(page, disp)
- ; where: page ----- page number
- ; disp ----- (byte) displacement within page
- ;************************************************************************
- PROC C get_word, @@page:WORD, @@disp:WORD
- mov bx, [@@page]
- shl bx, 1 ; adjust it for segment lookup
- ldpage es, bx
- mov bx, [@@disp]
- mov ax, [WORD es:bx]
- ret
- ENDP get_word
-
- ;************************************************************************
- ; Put a byte of data
- ; Calling sequence: put_byte(page, disp, value)
- ; where: page ----- page number
- ; disp ----- (byte) displacement within page
- ; value ---- value to be stored (low order 8 bits)
- ;************************************************************************
- PROC C put_byte, @@page:WORD, @@disp:WORD, @@val:WORD
- mov bx, [@@page]
- shl bx, 1 ; adjust it for segment lookup
- ldpage es, bx
- mov bx, [@@disp]
- mov ax, [@@val]
- mov [BYTE es:bx], al
- ret
- ENDP put_byte
-
- ;************************************************************************
- ; Put a word of data
- ; Calling sequence: put_word(page, disp, value)
- ; where: page ----- page number
- ; disp ----- (byte) displacement within page
- ; value ---- value to be stored (16 bits)
- ;************************************************************************
- PROC C put_word, @@page:WORD, @@disp:WORD, @@val:WORD
- mov bx, [@@page]
- shl bx, 1 ; adjust it for segment lookup
- ldpage es, bx
- mov bx, [@@disp]
- mov ax, [@@val]
- mov [WORD es:bx], ax
- ret
- ENDP put_word
-
- ;************************************************************************
- ; Put a pointer
- ; Calling sequence: put_word(page, disp, pg_value, ds_value)
- ; where: old_data - original data (overwritten)
- ; page ----- page number
- ; disp ----- (byte) displacement within page
- ; pg_value ---- value of page number to store (16 bits)
- ; ds_value ---- value of displacement to store (16 bits)
- ;************************************************************************
- PROC C put_ptr, @@page:WORD, @@disp:WORD, @@ptpage:WORD, @@ptdisp:WORD
- mov bx, [@@page]
- sal bx, 1
- ldpage es, bx
- mov bx, [@@disp]
- mov ax, [@@ptpage]
- mov [(POINTER es:bx).page], al
- mov ax, [@@ptdisp]
- mov [(POINTER es:bx).disp], ax
- ret
- ENDP put_ptr
-
- ;************************************************************************
- ;* get_str, get_sym *
- ;************************************************************************
- PROC C get_str USES ds si di, @@ptr:WORD, @@page:WORD, @@disp:WORD
- push ds ; Assume es = ds
- pop es
- mov di, [@@ptr]
- mov bx, [@@page]
- shl bx, 1 ; Adjust page number for use as index
- ldpage ds, bx
- mov si, [@@disp]
- sstrlen cx, <si>
- lea si, [(STRDEF si).buffer]
- cld
- rep movsb
- ret
- ENDP get_str
-
- PROC C get_sym USES ds si di, @@ptr:WORD, @@page:WORD, @@disp:WORD
- push ds ; Assume es = ds
- pop es
- mov di, [@@ptr]
- mov bx, [@@page]
- shl bx, 1 ; Adjust page number for use as index
- ldpage ds, bx
- mov si, [@@disp]
- mov cx, [(SYMDEF si).len]
- add si, OFFSET (TYPE SYMDEF).buffer
- sub cx, OFFSET (TYPE SYMDEF).buffer
- cld
- rep movsb
- ret
- ENDP get_sym
-
- ;************************************************************************
- ;* put_str, put_sym *
- ;************************************************************************
- PROC C put_str USES si di, @@ptr:WORD, @@page:WORD, @@disp:WORD
- mov bx, [@@page]
- shl bx, 1 ; Adjust page number for use as index
- ldpage es, bx
- mov si, [@@ptr]
- mov di, [@@disp]
- sstrlen cx, <es:di>
- lea di, [(STRDEF es:di).buffer]
- cld
- rep movsb
- ret
- ENDP put_str
-
- PROC C put_sym USES si di, @@ptr:WORD, @@page:WORD, @@disp:WORD, @@linkpage:WORD, @@linkdisp:WORD, @@hashkey:WORD
- mov bx, [@@page]
- shl bx, 1 ; Adjust page number for use as index
- ldpage es, bx
- mov si, [@@ptr]
- mov di, [@@disp]
- mov dx, [@@linkpage]
- mov ax, [@@linkdisp]
- mov [(SYMDEF es:di).link.page], dl
- mov [(SYMDEF es:di).link.disp], ax
- mov ax, [@@hashkey]
- mov [(SYMDEF es:di).hashkey], al
-
- mov cx, [(SYMDEF es:di).len]
- lea di, [(SYMDEF es:di).buffer]
- sub cx, OFFSET (TYPE SYMDEF).buffer
- cld
- rep movsb
- ret
- ENDP put_sym
-
- ;************************************************************************
- ;* Convert page, displacement values to a long integer *
- ;************************************************************************
- PROC C make_ptr, @@page:WORD, @@disp:WORD
- mov dx, [@@page]
- adjpage dx
- mov ax, [@@disp]
- ret
- ENDP make_ptr
-
- ;************************************************************************
- ;* Allocate a cell for a fixnum (actually, return an immediate value) *
- ;* Calling sequence: alloc_fixnum(®, value) *
- ;************************************************************************
- PROC C alloc_fixnum, @@reg:WORD, @@val:WORD
- mov bx, [@@reg]
- mov ax, [@@val]
- mov [(REG bx).disp], ax
- mov [(REG bx).page], SPECFIX*2
- ret
- ENDP alloc_fixnum
-
- ;************************************************************************
- ;* Copy Variable Length Data Object *
- ;* *
- ;* Purpose: To create a copy of a variable length Scheme data object. *
- ;* *
- ;* Calling Sequence: copy_blk(&dest, &src) *
- ;* where &dest: address of VM register into which pointer to *
- ;* new copy is to be placed *
- ;* &src: address of VM register containing block to be copied *
- ;************************************************************************
- PROC C copy_blk USES ds si di, @@dest:WORD, @@src:WORD
- mov si, [@@src]
- mov bx, [(REG si).page]
- mov di, [(REG si).disp]
- ldpage es, bx
-
- mov ax, [(ANYDEF es:di).len]
- or ax, ax
- jge @@bigblock
- add ax, SIZE POINTER
- jmp @@cont
- @@bigblock:
- sub ax, OFFSET (TYPE ANYDEF).data
- @@cont:
- xor bx, bx ; load type field from source block
- mov bl, [(ANYDEF es:di).tag]
-
- call alloc_block C, [@@dest], bx, ax
-
- mov bx, [@@dest]
- mov di, [(REG bx).disp]
- mov bx, [(REG bx).page]
- ldpage es, bx
-
- mov bx, [@@src]
- mov si, [(REG bx).disp]
- mov bx, [(REG bx).page]
- ldpage ds, bx
-
- sstrlen cx, <si>
- lea si, [(ANYDEF si).data]
- lea di, [(ANYDEF di).data]
- cld
- shr cx, 1
- rep movsw
- jnc @@even
- movsb
- @@even:
- ret
- ENDP copy_blk
-
- ;************************************************************************
- ;* C callable Routine to Take car/cdr of a List *
- ;************************************************************************
- PROC C take_car USES si, @@reg:WORD
- mov si, [@@reg]
- mov bx, [(REG si).page]
- cmp [ptype+bx], LISTTYPE
- jne take_error
- ldpage es, bx
- mov bx, [(REG si).disp]
- mov al, [(LISTDEF es:bx).car.page]
- mov bx, [(LISTDEF es:bx).car.disp]
- take_ok:
- mov [(REG si).bpage], al
- mov [(REG si).disp], bx
- ret
- take_error:
- xor ax, ax
- mov [(REG si).page], ax
- mov [(REG si).disp], ax
- ret
- ENDP take_car
-
- PROC C take_cdr USES si, @@reg:WORD
- mov si, [@@reg]
- mov bx, [(REG si).page]
- cmp [ptype+bx], LISTTYPE
- jne take_error
- ldpage es, bx
- mov bx, [(REG si).disp]
- mov al, [(LISTDEF es:bx).cdr.page]
- mov bx, [(LISTDEF es:bx).cdr.disp]
- jmp take_ok
- ENDP take_cdr
-
- ;************************************************************************
- ;* Symbol Hashing Routine *
- ;* *
- ;* Calling Seguence: hash_value = hash(symbol, len); *
- ;************************************************************************
- PROC C hash USES si, @@symbol:WORD, @@len:WORD
- mov si, [@@symbol]
- mov cx, [@@len]
- xor bx, bx
- xor ah, ah
- jcxz @@skiploop
- @@loop:
- lodsb
- add bx, ax ; sum them up
- rol bx, 1 ; complicate
- loop @@loop
- @@skiploop:
- mov ax, bx ; copy sum of chars to ax
- xor dx, dx
- mov bx, HT_SIZE
- div bx
- mov ax, dx
- ret
- ENDP hash
-
- ;************************************************************************
- ;* Symbol Equality Routine *
- ;* *
- ;* Calling Sequence: equal? = sym_eq(page, disp, symbol, len); *
- ;************************************************************************
- PROC C sym_eq USES es si di, @@page:WORD, @@disp:WORD, @@symbol:WORD, @@len:WORD
- mov bx, [@@page]
- shl bx, 1 ; and adjust for word indexing
- mov di, [@@disp]
- mov si, [@@symbol]
- mov cx, [@@len]
- ldpage es, bx
- mov bx, [(SYMDEF es:di).len]
- sub bx, OFFSET (TYPE SYMDEF).buffer
- cmp cx, bx ; length of symbol match?
- jne @@noteq
- add di, OFFSET (TYPE SYMDEF).buffer
- repe cmpsb
- jne @@noteq ; symbols the same? if not, jump
- mov ax, 1 ; return equality
- ret
- @@noteq:
- xor ax, ax ; zero ax (return false value)
- ret
- ENDP sym_eq
-
- ;************************************************************************
- ; Borland C callable routine to push a register onto Scheme's stack *
- ; Calling Sequence: C_push(c_reg) *
- ; where: REG c_reg: register (pointer/value) to push *
- ;************************************************************************
- PROC C c_push USES di, @@reg:WORD
- @@retry: ; Process overflow-- copy contents of stack to the heap
- mov di, [topofstack]
- cmp di, STKSIZE-SIZE POINTER; test for overflow
- jnge @@alright
- call stk_ovfl C ; copy the stack contents
- jmp @@retry
- @@alright:
- add di, SIZE POINTER
- mov [topofstack], di
- mov bx, [@@reg]
- mov dl, [(REG bx).bpage]
- mov ax, [(REG bx).disp]
- mov [(POINTER s_stack+di).page], dl
- mov [(POINTER s_stack+di).disp], ax
- ret
- ENDP c_push
-
- ;************************************************************************
- ; Borland C callable routine to pop a register from Scheme's stack *
- ; Calling Sequence: C_pop(c_reg) *
- ; where: REG c_reg: register to hold the value popped *
- ;************************************************************************
- PROC C c_pop USES si, @@reg:WORD
- mov si, [topofstack]
- lea ax, [si-SIZE POINTER]
- mov [topofstack], ax
- mov bx, [@@reg]
- mov dl, [(POINTER s_stack+si).page]
- mov ax, [(POINTER s_stack+si).disp]
- mov [(REG bx).bpage], dl
- mov [(REG bx).disp], ax
- ret
- ENDP c_pop
-
- ;************************************************************************
- ;* C-callable Fluid Variable Lookup *
- ;* *
- ;* Purpose: To retrieve the fluid binding for a variable. *
- ;* *
- ;* Calling Sequence: stat = fluid_lookup(®) *
- ;* where ®: address of the register containing the symbol to be *
- ;* looked up. *
- ;* On exit, "reg" contains the current binding for the *
- ;* symbol, if found. *
- ;* stat: search status: TRUE=symbol found *
- ;* FALSE=symbol not found *
- ;* *
- ;* Note: If the call to "lookup" doesn't find the desired symbol, it *
- ;* will return a nil pointer. It is correct to always *
- ;* return the cdr of the pointer "lookup" returns, since *
- ;* the cdr of nil is itself nil-- a valid value. *
- ;************************************************************************
- PROC C fluid_lookup USES si di, @@reg:WORD
- mov bx, [@@reg]
- mov ax, [(REG bx).disp]
- mov dl, [(REG bx).bpage]
- mov bx, [fnv_reg.page]
- mov si, [fnv_reg.disp]
- call lookup ; search the fluid environment for the symbol
- mov si, [@@reg] ; store "cdr" of returned cell into register
- mov dl, [(LISTDEF es:di).cdr.page]
- mov ax, [(LISTDEF es:di).cdr.disp]
- mov [(REG si).bpage], dl
- mov [(REG si).disp], ax
- mov ax, bx ; set return code (bx=0 if symbol not found)
- ret
- ENDP fluid_lookup
-
- ;************************************************************************
- ;* CPUTYPE and CPUSPEED *
- ;* *
- ;* Purpose: To determine to cpu type (8086, '186, '286, '386 etc.) *
- ;* and the processor's speed in MHz. *
- ;* CPUSPEED accepts two arguments, pointers to registers *
- ;************************************************************************
- PROC C cputype USES es si, @@type:WORD, @@speed:WORD
- xor ax, ax
- mov es, ax
- mov si, 46ch ; es:si is timer's address
-
- action <8086 ? >
- pushf
- pop bx ; try clearing bits 12-15
- and bx, 0fffh
- push bx
- popf
- pushf
- pop cx
- and cx, 0f000h ; if set, then it's a 8086
- cmp cx, 0f000h
- jne @@not8086
- jmp @@8086
- @@not8086:
- action <80286 ? >
- or bx, 0f000h ; now try to set them
- push bx
- popf
- pushf
- pop bx
- and bx, 0f000h ; if they're all clear, then it's a 286
- jnz @@32bit
-
- action <Measuring',13,10,'>
- mov bx, [@@type]
- mov [(REG bx).disp], 286
-
- xor cx, cx
- mov bx, [WORD es:si] ; read the timer
- @@start286:
- cmp [WORD es:si], bx
- je @@start286 ; wait for a clock rise
- mov bx, [WORD es:si] ; wait for the next one
- @@speed286:
- inc cx ; 2
- mul ax ; ax is 0, so timing=24
- cmp [WORD es:si], bx ; 7
- je @@speed286 ; 7
- mov ax, cx
- add ax, 687
- mov cx, 1374 ; 1000000 / (18.2 * 40)
- div cx
- jmp @@return
- @@32bit:
- P386
- action <80386 ? >
- mov edx, esp
- and esp, not 3 ; avoid stack faults
- pushfd
- pop eax
- mov ecx, eax
- xor eax, 40000h ; flip the Align-Check bit
- push eax
- popfd
- pushfd
- pop eax
- xor eax, ecx
- push ecx
- popfd
- mov esp, edx
- and eax, 40000h ; if flags didn't change there,
- jz @@386 ; alignment check is usupported.
-
- action <80486. Measuring',13,10,'>
- mov bx, [@@type]
- mov [(REG bx).disp], 486
- xor cx, cx
- mov bx, [WORD es:si] ; read the timer
- @@start486:
- cmp [WORD es:si], bx
- je @@start486 ; wait for a clock rise
- mov bx, [WORD es:si] ; wait for the next one
- @@speed486:
- inc cx ; 1
- imul eax, eax, 80000000h ; worst case: 42
- imul eax, eax, 80000000h
- cmp [WORD es:si], bx ; 2
- je @@speed486 ; 3
- mov ax, cx
- add ax, 305
- mov cx, 610 ; 1000000 / (18.2 * 90)
- xor dx, dx
- div cx
- jmp @@return
- @@386:
- action <Measuring',13,10,'>
- mov bx, [@@type]
- mov [(REG bx).disp], 386
- xor cx, cx
- mov bx, [WORD es:si] ; read the timer
- @@start386:
- cmp [WORD es:si], bx
- je @@start386 ; wait for a clock rise
- mov bx, [WORD es:si] ; wait for the next one
- @@speed386:
- inc cx ; 2
- imul eax, eax, 80000000h ; worst case: 38
- cmp [WORD es:si], bx ; 5
- je @@speed386 ; 7
- mov ax, cx
- add ax, 528
- mov cx, 1057 ; 1000000 / (18.2 * 52)
- xor dx, dx
- div cx
- jmp @@return
- P8086
- @@8086: ; just for fun, let's see if the data
- action <Measuring',13,10,'> ; path is 8 or 16 bits
- xor dx, dx
- mov bx, [WORD es:si] ; read the timer
- @@start86:
- cmp [WORD es:si], bx
- je @@start86 ; wait for a clock rise
- mov bx, [WORD es:si] ; wait for the next one
- @@loop16:
- inc ax ; 2
- cmp [WORD es:si], bx ; 4 * (14..18)
- cmp [WORD es:si], bx
- cmp [WORD es:si], bx
- cmp [WORD es:si], bx
- je @@loop16 ; 16
- inc bx ; go for another one
- @@loop8:
- inc dx
- cmp [BYTE es:si], bl
- cmp [BYTE es:si], bl
- cmp [BYTE es:si], bl
- cmp [BYTE es:si], bl
- je @@loop8 ; now dx should be 90/74 ax
-
- mov si, [@@type]
- mov bx, dx
- sub dx, ax
- idiv ax
- cmp ax, 7000 ; more than 10% below ?
- jl @@16bit
- mov [(REG si).disp], 88
- jmp @@speed86
- @@16bit:
- mov [(REG si).disp], 86
- @@speed86:
- mov ax, bx
- add ax, 371 ; half for roundoffs
- mov bx, 742 ; 1000000 / (74 * 18.21)
- xor dx, dx
- div bx
- @@return:
- action <Leaving CPU test subroutine',13,10,'>
- mov si, [@@speed]
- mov [(REG si).disp], ax
- ret
- ENDP cputype
-
- END